package com.first.computerstore.controller;

import com.first.computerstore.controller.exception.*;
import com.first.computerstore.service.UserService;
import com.first.computerstore.utils.JsonResult;
import com.first.computerstore.entity.User;
import com.google.code.kaptcha.Constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;


/**
 * @description: 处理用户请求的控制器
 */
@RestController
@RequestMapping("/user")
public class UserController extends BaseController{

    @Resource
    private UserService userService;
    @Value("${server.ip}")
    private String ip;
    @Value("${server.port}")
    private String port;

    //用户注册
    @PostMapping("/register")
    public JsonResult<Void> userRegister(User user, HttpSession session, String code) {
        //从session取出验证码
        String validCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        //判断验证码是否一致
        if (!validCode.equals(code)){
            throw new ValidCodeNotMatchException("验证码错误,请重试！");
        }
        //执行插入操作
        userService.userRegister(user);
        return new JsonResult<>(OK);
    }

    //用户登录
    @GetMapping("/login")
    public JsonResult<User> userLogin(User user, HttpSession session,String code){
        //将存储在session的kaptcha所生成的验证码取出
        String validCode = (String) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        //判断验证码是否一致
        if (!validCode.equals(code)){
            throw new ValidCodeNotMatchException("验证码错误,请重试！");
        }
        //执行登录操作
        User loginUser = userService.userLogin(user);
        //分别将用户的session保存到服务端
        session.setAttribute("uid",loginUser.getUid());
        session.setAttribute("username",loginUser.getUsername());
        //优化一下传回前端的user数据，有些字段是不需要的。
        //只将用户名和uid进行回传
        User newUser = new User();
        newUser.setUsername(loginUser.getUsername());
        newUser.setUid(loginUser.getUid());
        newUser.setGender(loginUser.getGender());
        newUser.setPhone(loginUser.getPhone());
        newUser.setEmail(loginUser.getEmail());
        newUser.setAvatar(loginUser.getAvatar());

        return new JsonResult<>(OK,newUser);
    }

    @GetMapping("/queryUser")
    public JsonResult<User> queryUserByUid(HttpSession session){
        Integer uid = getUserIdFromSession(session);

        User user = userService.queryUserByUid(uid);

        //将用户名、id、电话、邮箱、性别进行回传
        User newUser = new User();
        newUser.setUsername(user.getUsername());
        newUser.setUid(user.getUid());
        newUser.setGender(user.getGender());
        newUser.setPhone(user.getPhone());
        newUser.setEmail(user.getEmail());
        newUser.setAvatar(user.getAvatar());

        return new JsonResult<>(OK,newUser);
    }

    @GetMapping("/exit")
    public JsonResult<Void> exitUserLoginStatus(HttpSession session){
        session.removeAttribute("username");
        session.removeAttribute("uid");
        return new JsonResult<>(OK);
    }

    /*设置文件可以上传的最大值*/
    public static final int  AVATAR_MAX_SIZE= 10*1024*1024 ;
    /*设置文件可以上传的类型*/
    public static final List<String> AVATAR_TYPE=new ArrayList<>();
    static {
        AVATAR_TYPE.add("image/jpeg");
        AVATAR_TYPE.add("image/png");
        AVATAR_TYPE.add("image/bmp");
        AVATAR_TYPE.add("image/gif");
        AVATAR_TYPE.add("image/jpg");
    }


    /**
     * 上传头像
     * @param session
     * @param file
     * @return
     */
    @PostMapping("/uploadHeader")
    public JsonResult uploadHeader(HttpSession session,@RequestParam("file") MultipartFile file) {
        JsonResult result = new JsonResult<>();

        //  判断文件是否为空
        if (null == file) {
            throw new FileEmptyException("文件不能为空");
        }
        //  判断文件大小是否超出限制
        if (file.getSize() > AVATAR_MAX_SIZE) {
            throw new FileSizeException("文件超出限制");
        }

        //  判断文件类型是否正确
        String contentType = file.getContentType();

        if (!AVATAR_TYPE.contains(contentType)) {

            throw new FileTypeNotMatchException("文件类型不支持！");
        }
        //获取上传文件的原始名字
        String originalFilename = file.getOriginalFilename();

        //获取文件的后缀名
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));

        //使用时间戳为文件定义新的名字
        String uuidName = UUID.randomUUID().toString();

        //定义文件最终的名字
        String fileName = uuidName + suffix;

        //获取项目在服务器上的真实位置并拼凑文件最终的保存位置
        //本地的写法
        String realPath = System.getProperty("user.dir") + "/src/main/resources/static/images/img/" + fileName;

        /**
         * 这里其实有两个选择：①直接将文件写入硬盘 这里选择这种
         * ②先获取存储文件的文件夹的路径，判断存储文件的文件夹是否存在，不存在则创建
         * 最后再将文件名和文件夹路径进行拼凑出最终文件的保存路径
         **/
        //虚拟创建目标文件
        File destFile = new File(realPath);

        //获取目标文件的上级目录
        File parentFile = destFile.getParentFile();

        if (!parentFile.exists()){
            //代表文件的上级目录不存在，进行创建
            parentFile.mkdirs();
        }

        //选择第一种方法，直接写入目标位置
        try {
            file.transferTo(destFile);
        }catch (FileStatusException e) {
            throw new FileStatusException("文件状态异常，写入失败");
        }catch (IOException e) {
            throw new FileUploadIOException("服务器或数据库写入文件失败");
        }

        //获取uid值
        Integer uid = getUserIdFromSession(session);
        String userName = getUsernameFromSession(session);

        String fileAccessPath = "http://" + ip + ":" + port + "/user/uploadHeader/file/down/" + fileName;

        userService.uploadHeader(uid,fileAccessPath,userName);

        result.setStatus(200);
        result.setMessage("头像上传成功O(∩_∩)O");
        result.setData(fileAccessPath);
       return result;
    }

    /**
     * 修改密码
     *      通过session获取uid
     *      进行参数校验，得到jsonResult对象
     *      返回 JsonResult
     * @param oldPwd
     * @param password
     * @param rePwd
     * @param session
     * @return
     */
    @PostMapping("/resetPassword")
    public JsonResult<Void> updatePassWord(String oldPwd, String password, String rePwd,HttpSession session){
        Integer uid = getUserIdFromSession(session);
        JsonResult jsonResult = userService.selectPassWord(oldPwd,password,rePwd,uid);

        return jsonResult;
    }

    //更新个人资料
    @PostMapping("updateInfo")
    public JsonResult<User> updateUserInfo(String phone,String email,Integer gender,HttpSession session){
        //从session作用域中获取用户名和id
        String username=getUsernameFromSession(session);
        Integer uid=getUserIdFromSession(session);
        //调用业务逻辑层的更新方法，得到更新后的用户对象
        User user=userService.updateUserInfo(phone,email,gender,uid,username);
        //返回更新后的用户对象
        return new JsonResult<>(OK,user);
    }


    /**
     * Description : 处理文件的下载
     * @param fileName 下载的文件名
     * @return org.springframework.http.ResponseEntity<byte[]>
     **/
    @GetMapping("/uploadHeader/file/down/{name}")
    public ResponseEntity<byte[]> fileUpload(@PathVariable("name") String fileName) throws IOException {
        //读取文件
        //本地读取路径的写法
        String downFilePath = System.getProperty("user.dir") + "/src/main/resources/static/images/img/" + fileName;

        if (downFilePath != null){
            //创建一个输入流读入需要下载的文件
            FileInputStream inputStream = new FileInputStream(new File(downFilePath));

            //创建一个和文件所需字节大小一致的byte字节数组
            byte[] fileBytes = new byte[inputStream.available()];

            //将读入的流写入字节数据
            inputStream.read(fileBytes);

            //创建HttpHeaders对象设置响应头信息
            HttpHeaders headers = new HttpHeaders();

            //设置要下载方式以及下载文件的名字
            //Content-Disposition 通知客户端以下载的方式接受数据
            //attachment;filename= 设置下载的文件的名字
            headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName,"UTF-8"));

            //设置响应状态码
            HttpStatus statusCode = HttpStatus.OK;

            //创建ResponseEntity对象
            ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(fileBytes, headers, statusCode);

            //关闭输入流
            inputStream.close();
            //将需要下载的文件以字节数组的方式响应出去
            return responseEntity;
        }
        return null;
    }
}
